using ERP.Common.Results;
using ERP.Team.ProductionSystem;
using ERP.ERPSystem.ProductionSystem.Dto;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace ERP.ERPSystem.ProductionSystem
{
    /// <summary>
    /// 生产排产服务实现
    /// </summary>
    public class ProductionSchedulingServices : ApplicationService, IProductionSchedulingServices
    {
        private readonly IRepository<ProductionSchedulingModel, int> _productionSchedulingRepository;

        public ProductionSchedulingServices(IRepository<ProductionSchedulingModel, int> productionSchedulingRepository)
        {
            _productionSchedulingRepository = productionSchedulingRepository;
        }

        /// <summary>
        /// 分页查询生产排产列表
        /// </summary>
        /// <param name="queryDto">查询条件</param>
        /// <returns>分页排产列表</returns>
        public async Task<APIPaging<ProductionSchedulingModel>> GetProductionSchedulingList(ProductionSchedulingQueryDto queryDto)
        {
            try
            {
                var pageList = new APIPaging<ProductionSchedulingModel>();
                var query = await _productionSchedulingRepository.GetQueryableAsync();

                // 条件筛选
                query = query.WhereIf(!string.IsNullOrEmpty(queryDto.WorkOrderCode),
                    m => m.WorkOrderCode.Contains(queryDto.WorkOrderCode));

                query = query.WhereIf(!string.IsNullOrEmpty(queryDto.WorkOrderName),
                    m => m.WorkOrderName.Contains(queryDto.WorkOrderName));

                query = query.WhereIf(!string.IsNullOrEmpty(queryDto.SourceDocumentNo),
                    m => m.SourceDocumentNo.Contains(queryDto.SourceDocumentNo));

                query = query.WhereIf(!string.IsNullOrEmpty(queryDto.ProductCode),
                    m => m.ProductCode.Contains(queryDto.ProductCode));

                query = query.WhereIf(!string.IsNullOrEmpty(queryDto.ProcessCode),
                    m => m.ProcessCode.Contains(queryDto.ProcessCode));

                // 日期范围筛选
                if (queryDto.StartDate.HasValue)
                {
                    query = query.Where(m => m.RecordCreateTime >= queryDto.StartDate.Value);
                }

                if (queryDto.EndDate.HasValue)
                {
                    var endDate = queryDto.EndDate.Value.Date.AddDays(1);
                    query = query.Where(m => m.RecordCreateTime < endDate);
                }

                // 计算总数
                pageList.PageCount = query.Count();

                // 分页和排序
                pageList.ListDate = query
                    .OrderByDescending(m => m.RecordUpdateTime)
                    .Skip((queryDto.Page - 1) * queryDto.Limit)
                    .Take(queryDto.Limit)
                    .ToList();

                // 计算总页数
                pageList.PageIndex = Convert.ToInt32(Math.Ceiling(pageList.PageCount * 1.0 / queryDto.Limit));

                return pageList;
            }
            catch (Exception ex)
            {
                throw new Exception($"查询生产排产列表失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 根据ID获取生产排产详情
        /// </summary>
        /// <param name="id">排产ID</param>
        /// <returns>排产详情</returns>
        public async Task<ProductionSchedulingModel> GetProductionSchedulingById(int id)
        {
            try
            {
                var scheduling = await _productionSchedulingRepository.FirstOrDefaultAsync(x => x.Id == id);
                if (scheduling == null)
                {
                    throw new ArgumentException($"排产ID {id} 不存在");
                }
                return scheduling;
            }
            catch (Exception ex)
            {
                throw new Exception($"获取生产排产详情失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 添加生产排产
        /// </summary>
        /// <param name="productionSchedulingDto">生产排产信息</param>
        /// <returns>排产ID</returns>
        public async Task<int> AddProductionScheduling(ProductionSchedulingDto productionSchedulingDto)
        {
            try
            {
                // 验证必需字段
                if (string.IsNullOrEmpty(productionSchedulingDto.WorkOrderCode))
                    throw new ArgumentException("工单编码不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.WorkOrderName))
                    throw new ArgumentException("工单名称不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.SourceDocumentNo))
                    throw new ArgumentException("来源单据号不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.ProductCode))
                    throw new ArgumentException("产品编码不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.ProcessCode))
                    throw new ArgumentException("工序编码不能为空");

                // 检查工单编码是否已存在
                var existingScheduling = await _productionSchedulingRepository.FirstOrDefaultAsync(
                    x => x.WorkOrderCode == productionSchedulingDto.WorkOrderCode);
                if (existingScheduling != null)
                {
                    throw new ArgumentException($"工单编码 {productionSchedulingDto.WorkOrderCode} 已存在");
                }

                // 创建生产排产实体
                var productionScheduling = new ProductionSchedulingModel
                {
                    WorkOrderCode = productionSchedulingDto.WorkOrderCode ?? "",
                    WorkOrderName = productionSchedulingDto.WorkOrderName ?? "",
                    SourceDocumentNo = productionSchedulingDto.SourceDocumentNo ?? "",
                    ProductCode = productionSchedulingDto.ProductCode ?? "",
                    ProductModel = productionSchedulingDto.ProductModel ?? "",
                    ProcessCode = productionSchedulingDto.ProcessCode ?? "",
                    AdjustQuantity = productionSchedulingDto.AdjustQuantity,
                    RecordCreateTime = DateTime.Now,
                    RecordUpdateTime = DateTime.Now
                };

                // 插入到数据库并保存更改
                var result = await _productionSchedulingRepository.InsertAsync(productionScheduling, autoSave: true);

                return result.Id;
            }
            catch (Exception ex)
            {
                throw new Exception($"添加生产排产失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 更新生产排产
        /// </summary>
        /// <param name="productionSchedulingDto">生产排产信息</param>
        /// <returns>更新结果</returns>
        public async Task<bool> UpdateProductionScheduling(ProductionSchedulingDto productionSchedulingDto)
        {
            try
            {
                // 验证排产是否存在
                var existingScheduling = await _productionSchedulingRepository.FirstOrDefaultAsync(x => x.Id == productionSchedulingDto.Id);
                if (existingScheduling == null)
                {
                    throw new ArgumentException($"排产ID {productionSchedulingDto.Id} 不存在");
                }

                // 验证必需字段
                if (string.IsNullOrEmpty(productionSchedulingDto.WorkOrderCode))
                    throw new ArgumentException("工单编码不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.WorkOrderName))
                    throw new ArgumentException("工单名称不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.SourceDocumentNo))
                    throw new ArgumentException("来源单据号不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.ProductCode))
                    throw new ArgumentException("产品编码不能为空");
                if (string.IsNullOrEmpty(productionSchedulingDto.ProcessCode))
                    throw new ArgumentException("工序编码不能为空");

                // 检查工单编码是否被其他记录使用
                var duplicateScheduling = await _productionSchedulingRepository.FirstOrDefaultAsync(
                    x => x.WorkOrderCode == productionSchedulingDto.WorkOrderCode && x.Id != productionSchedulingDto.Id);
                if (duplicateScheduling != null)
                {
                    throw new ArgumentException($"工单编码 {productionSchedulingDto.WorkOrderCode} 已被其他记录使用");
                }

                // 更新排产信息
                existingScheduling.WorkOrderCode = productionSchedulingDto.WorkOrderCode ?? "";
                existingScheduling.WorkOrderName = productionSchedulingDto.WorkOrderName ?? "";
                existingScheduling.SourceDocumentNo = productionSchedulingDto.SourceDocumentNo ?? "";
                existingScheduling.ProductCode = productionSchedulingDto.ProductCode ?? "";
                existingScheduling.ProductModel = productionSchedulingDto.ProductModel ?? "";
                existingScheduling.ProcessCode = productionSchedulingDto.ProcessCode ?? "";
                existingScheduling.AdjustQuantity = productionSchedulingDto.AdjustQuantity;
                existingScheduling.RecordUpdateTime = DateTime.Now;

                // 保存更改
                await _productionSchedulingRepository.UpdateAsync(existingScheduling, autoSave: true);

                return true;
            }
            catch (Exception ex)
            {
                throw new Exception($"更新生产排产失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 批量删除生产排产
        /// </summary>
        /// <param name="ids">排产ID数组</param>
        /// <returns>删除结果</returns>
        public async Task<bool> DeleteProductionSchedulings(int[] ids)
        {
            try
            {
                if (ids == null || ids.Length == 0)
                {
                    throw new ArgumentException("删除的排产ID不能为空");
                }

                // 验证所有排产是否存在
                var schedulings = await _productionSchedulingRepository.GetListAsync(x => ids.Contains(x.Id));
                if (schedulings.Count != ids.Length)
                {
                    var existingIds = schedulings.Select(x => x.Id).ToArray();
                    var missingIds = ids.Except(existingIds).ToArray();
                    throw new ArgumentException($"以下排产ID不存在: {string.Join(", ", missingIds)}");
                }

                // 执行批量删除
                await _productionSchedulingRepository.DeleteManyAsync(schedulings, autoSave: true);

                return true;
            }
            catch (Exception ex)
            {
                throw new Exception($"批量删除生产排产失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 根据工单编码获取排产信息
        /// </summary>
        /// <param name="workOrderCode">工单编码</param>
        /// <returns>排产信息</returns>
        public async Task<ProductionSchedulingModel> GetProductionSchedulingByWorkOrderCode(string workOrderCode)
        {
            try
            {
                if (string.IsNullOrEmpty(workOrderCode))
                {
                    throw new ArgumentException("工单编码不能为空");
                }

                var scheduling = await _productionSchedulingRepository.FirstOrDefaultAsync(
                    x => x.WorkOrderCode == workOrderCode);
                
                return scheduling;
            }
            catch (Exception ex)
            {
                throw new Exception($"根据工单编码获取排产信息失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 根据工单编码和产品编码获取排产信息
        /// </summary>
        /// <param name="workOrderCode">工单编码</param>
        /// <param name="productCode">产品编码</param>
        /// <returns>排产信息</returns>
        public async Task<ProductionSchedulingModel> GetProductionSchedulingByWorkOrderAndProduct(string workOrderCode, string productCode)
        {
            try
            {
                if (string.IsNullOrEmpty(workOrderCode))
                {
                    throw new ArgumentException("工单编码不能为空");
                }

                var query = await _productionSchedulingRepository.GetQueryableAsync();
                var scheduling = query.Where(x => x.WorkOrderCode == workOrderCode);
                
                if (!string.IsNullOrEmpty(productCode))
                {
                    scheduling = scheduling.Where(x => x.ProductCode == productCode);
                }
                
                return scheduling.FirstOrDefault();
            }
            catch (Exception ex)
            {
                throw new Exception($"根据工单编码和产品编码获取排产信息失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 根据来源单据号获取排产列表
        /// </summary>
        /// <param name="sourceDocumentNo">来源单据号</param>
        /// <returns>排产列表</returns>
        public async Task<APIPaging<ProductionSchedulingModel>> GetProductionSchedulingBySourceDocument(string sourceDocumentNo, int page = 1, int limit = 10)
        {
            try
            {
                if (string.IsNullOrEmpty(sourceDocumentNo))
                {
                    throw new ArgumentException("来源单据号不能为空");
                }

                var pageList = new APIPaging<ProductionSchedulingModel>();
                var query = await _productionSchedulingRepository.GetQueryableAsync();

                query = query.Where(m => m.SourceDocumentNo == sourceDocumentNo);

                // 计算总数
                pageList.PageCount = query.Count();

                // 分页和排序
                pageList.ListDate = query
                    .OrderByDescending(m => m.RecordUpdateTime)
                    .Skip((page - 1) * limit)
                    .Take(limit)
                    .ToList();

                // 计算总页数
                pageList.PageIndex = Convert.ToInt32(Math.Ceiling(pageList.PageCount * 1.0 / limit));

                return pageList;
            }
            catch (Exception ex)
            {
                throw new Exception($"根据来源单据号获取排产列表失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 调整排产数量
        /// </summary>
        /// <param name="id">排产ID</param>
        /// <param name="adjustQuantity">调整数量</param>
        /// <returns>调整结果</returns>
        public async Task<bool> AdjustProductionQuantity(int id, int adjustQuantity)
        {
            try
            {
                var scheduling = await _productionSchedulingRepository.FirstOrDefaultAsync(x => x.Id == id);
                if (scheduling == null)
                {
                    throw new ArgumentException($"排产ID {id} 不存在");
                }

                scheduling.AdjustQuantity = adjustQuantity;
                scheduling.RecordUpdateTime = DateTime.Now;

                await _productionSchedulingRepository.UpdateAsync(scheduling, autoSave: true);

                return true;
            }
            catch (Exception ex)
            {
                throw new Exception($"调整排产数量失败: {ex.Message}", ex);
            }
        }
    }
} 